package org.github.xhjcehust.dubbo.proxy.controller;

import cn.htd.framework.common.BasePager;
import cn.htd.framework.common.BasePagerRequestParam;
import cn.htd.framework.common.BaseRequestParam;
import com.alibaba.fastjson.JSONObject;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.service.GenericService;
import org.github.xhjcehust.dubbo.proxy.common.CommonTools;
import org.github.xhjcehust.dubbo.proxy.model.DubboInvokerParam;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author xiaohengjin<xiaohengjin@corp.netease.com>
 * @date 2019/7/26
 */
@Controller
@RequestMapping("/dubboInvoker")
public class DubboInvokerHTD {

    @Value("${dubbo.registry.address}")
    private String registryAddress;

    @Value("${application.invoker.name}")
    private String appName;

    @Value("${dubbo.registry.version}")
    private String version;

    private final static String METHOD_TYPE_BASEREQUESTPARAM = "cn.htd.framework.common.BaseRequestParam";
    private final static String METHOD_TYPE_PAGER = "cn.htd.framework.common.BasePager";
    private final static String METHOD_TYPE_BASEPAGERREQUESTPARAM = "cn.htd.framework.common.BasePagerRequestParam";
    static List<String> extraArgTypes = new ArrayList<>();
    static {
        extraArgTypes.add(METHOD_TYPE_PAGER);
        extraArgTypes.add(METHOD_TYPE_BASEPAGERREQUESTPARAM);
    }

    /**
     * 汇通达业务
     * @param param
     * @return
     */
    @RequestMapping("/indexHTD")
    @ResponseBody
    public Object indexHTD(@RequestBody(required = false) DubboInvokerParam param) {
        String msg = CommonTools.check(param);
        if(msg != null){
            return msg;
        }

        return doInvokeHTD(param);
    }

    /**
     * 适配native-cloud-user等汇通达业务
     * @param param
     * @return
     */
    private Object doInvokeHTD(DubboInvokerParam param) {

        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
        reference.setApplication(new ApplicationConfig(appName));

        reference.setInterface(param.getInterfaceName());
        reference.setVersion(version);
        reference.setGeneric(true);
        reference.setGroup(param.getGroup());
        reference.setId(param.getId());
        reference.setTimeout(60000);
        reference.setRetries(0);

        RegistryConfig registry = new RegistryConfig();
        registry.setAddress(registryAddress);
        reference.setRegistry(registry);

        GenericService genericService = reference.get();

        Map<String, String> attachments = param.getAttachments();
        if (attachments != null) {
            RpcContext.getContext().setAttachments(attachments);
        }

        BaseRequestParam<Object> requestParam = new BaseRequestParam();
        BasePagerRequestParam<Object> requestBasePagerParam = new BasePagerRequestParam<>();
        BasePager pager = null;
        int type = 0;
        if(param.getArgTypes().length>0){
            String [] argTypes = new String[param.getArgTypes().length];
            Map<String,?> map = (Map) param.getArgObjects()[0];
            if(map.containsKey("current")&&map.containsKey("size")){
                try {
                    if(param.getArgTypes()[0].contains("java.lang")){
                        for(Map.Entry<String,?> entry : map.entrySet()){
                            if(!entry.getKey().equalsIgnoreCase("current")&&!entry.getKey().equalsIgnoreCase("size")){
                                switch (param.getArgTypes()[0]){
                                    case "java.lang.Long":
                                        requestBasePagerParam.setBusinessBody(Long.parseLong(entry.getValue().toString()));
                                        break;
                                    case "java.lang.Integer":
                                        requestBasePagerParam.setBusinessBody(Integer.parseInt(entry.getValue().toString()));
                                        break;
                                    case "java.lang.Double":
                                        requestBasePagerParam.setBusinessBody(Double.parseDouble(entry.getValue().toString()));
                                        break;
                                    case "java.lang.Float":
                                        requestBasePagerParam.setBusinessBody(Float.parseFloat(entry.getValue().toString()));
                                        break;
                                    case "java.lang.String":
                                        requestBasePagerParam.setBusinessBody(entry.getValue().toString());
                                        break;
                                }
                            }
                        }
                    }else{
                        Class cls = Class.forName(param.getArgTypes()[0]);
                        Object obj = JSONObject.parseObject(JSONObject.toJSONString(param.getArgObjects()[0]), cls);
                        requestBasePagerParam.setBusinessBody(obj);
                    }
                    pager = new BasePager();
                    pager.setCurrent(Integer.parseInt(map.get("current").toString()));
                    pager.setSize(Integer.parseInt(map.get("size").toString()));
                    requestBasePagerParam.setBasePager(pager);
                    argTypes[0] = METHOD_TYPE_BASEPAGERREQUESTPARAM;
                    type = 1;
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }else{
                for(int i=0,l=param.getArgTypes().length;i<l;i++){
                    if(METHOD_TYPE_PAGER.contains(param.getArgTypes()[i])){
                        pager = JSONObject.parseObject(JSONObject.toJSONString(param.getArgObjects()[i]), BasePager.class);
                        argTypes[i] = METHOD_TYPE_PAGER;
                        type = 2;
                    }else if(param.getArgTypes()[0].contains("java.lang")){
                        for(Map.Entry<String,?> entry : map.entrySet()){
                            if(!entry.getKey().equalsIgnoreCase("current")&&!entry.getKey().equalsIgnoreCase("size")){
                                switch (param.getArgTypes()[0]){
                                    case "java.lang.Long":
                                        requestParam.setBusinessBody(Long.parseLong(entry.getValue().toString()));
                                        break;
                                    case "java.lang.Integer":
                                        requestParam.setBusinessBody(Integer.parseInt(entry.getValue().toString()));
                                        break;
                                    case "java.lang.Double":
                                        requestParam.setBusinessBody(Double.parseDouble(entry.getValue().toString()));
                                        break;
                                    case "java.lang.Float":
                                        requestParam.setBusinessBody(Float.parseFloat(entry.getValue().toString()));
                                        break;
                                    case "java.lang.String":
                                        requestParam.setBusinessBody(entry.getValue().toString());
                                        break;
                                }
                            }
                        }
                        type = 3;
                        argTypes[i] = METHOD_TYPE_BASEREQUESTPARAM;
                    }else{
                        try {
                            Class cls = Class.forName(param.getArgTypes()[i]);
                            Object obj = JSONObject.parseObject(JSONObject.toJSONString(param.getArgObjects()[i]), cls);
                            requestParam.setBusinessBody(obj);
                            argTypes[i] = METHOD_TYPE_BASEREQUESTPARAM;
                            type = 3;
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            Object [] objects = null;
            Object result = null;
            switch (type){
                case 1:
                    objects = new Object[]{requestBasePagerParam};
                    result = genericService.$invoke(param.getMethodName(), argTypes, objects);
                    System.out.println(result);
                    return result;
                case 2:
                    objects = new Object[]{requestParam, pager};
                    result = genericService.$invoke(param.getMethodName(), argTypes, objects);
                    System.out.println(result);
                    return result;
                case 3:
                    objects = new Object[]{requestParam};
                    result = genericService.$invoke(param.getMethodName(), argTypes, objects);
                    System.out.println(result);
                    return result;
            }
        }

        Object result = genericService.$invoke(param.getMethodName(), null, null);
        System.out.println(result);
        return result;

    }

}
